﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using ParsecParser.Helpers;
using ParsecParser.Data;

namespace ParsecParser.Display
{
    public static class CombatEventFilters
    {
        public static bool IsSource(this CombatLogEvent x)
        {
            if (x.Source == null)
                return false;
            return x.Source.IsThisPlayer;
        }
        public static Expression<Func<CombatLogEvent, bool>> IsSource()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsSource());
        }
        public static bool IsDamage(this CombatLogEvent x)
        {
            if (x.EffectName == null)
                return false;
            return x.EffectName.EntityId == CombatLogConstants.EffectNames.Damage;
        }
        public static Expression<Func<CombatLogEvent, bool>> IsDamage()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsDamage());
        }
        public static bool IsTarget(this CombatLogEvent x)
        {
            if (x.Target == null)
                return false;
            return x.Target.IsThisPlayer;
        }
        public static Expression<Func<CombatLogEvent, bool>> IsTarget()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsTarget());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsNotTarget()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => !x.IsTarget());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsNotSource()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => !x.IsSource());
        }
        public static bool IsHeal(this CombatLogEvent x)
        {
            if (x.EffectName == null)
                return false;
            return x.EffectName.EntityId == CombatLogConstants.EffectNames.Heal;
        }
        public static Expression<Func<CombatLogEvent, bool>> IsHeal()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsHeal());
        }
        public static bool IsEffect(this CombatLogEvent x)
        {
            return x.IsEffectOn() || x.IsEffectOff();
        }
        public static bool IsEffectOn(this CombatLogEvent x)
        {
            if (x.EffectType == null || x.EffectName == null)
                return false;
            return (x.EffectType.EntityId == CombatLogConstants.EffectTypes.ApplyEffect && x.EffectName.EntityId != CombatLogConstants.EffectNames.Heal && x.EffectName.EntityId != CombatLogConstants.EffectNames.Damage);
        }
        public static bool IsEffectOff(this CombatLogEvent x)
        {
            if (x.EffectType == null)
                return false;
            return (x.EffectType.EntityId == CombatLogConstants.EffectTypes.RemoveEffect);
        }
        public static Expression<Func<CombatLogEvent, bool>> IsEffect()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsEffect());
        }
        public static bool IsTargetPlayerOrCompanion(this CombatLogEvent x)
        {
            if (x.Target == null)
                return false;
            return x.Target.IsPlayer || x.Target.IsPlayerCompanion;
        }
        public static Expression<Func<CombatLogEvent, bool>> TargetIsNotNpc()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsTargetPlayerOrCompanion());
        }
        private static long[] AbilityGroup = { CombatLogConstants.EffectNames.AbilityActivate, CombatLogConstants.EffectNames.AbilityCancel, CombatLogConstants.EffectNames.AbilityDeactivate, CombatLogConstants.EffectNames.AbilityInterrupt };
        public static bool IsAbility(this CombatLogEvent x)
        {
            if (x.EffectType == null || x.EffectName == null)
                return false;
            return x.EffectType.EntityId == CombatLogConstants.EffectTypes.Event && AbilityGroup.Contains(x.EffectName.EntityId);
        }
        public static bool IsAbilityActivate(this CombatLogEvent x)
        {
            if (x.EffectType == null || x.EffectName == null)
                return false;
            return x.EffectType.EntityId == CombatLogConstants.EffectTypes.Event && x.EffectName.EntityId == CombatLogConstants.EffectNames.AbilityActivate;
        }
        public static Expression<Func<CombatLogEvent, bool>> IsAbility()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsAbility());
        }
        private static long[] EventGroup = { CombatLogConstants.EffectNames.AbilityActivate, CombatLogConstants.EffectNames.AbilityCancel, CombatLogConstants.EffectNames.AbilityDeactivate, CombatLogConstants.EffectNames.AbilityInterrupt };
        public static bool IsEvent(this CombatLogEvent x)
        {
            if (x.EffectType == null || x.EffectName == null)
                return false;
            return x.EffectType.EntityId == CombatLogConstants.EffectTypes.Event && !AbilityGroup.Contains(x.EffectName.EntityId);
        }
        public static Expression<Func<CombatLogEvent, bool>> IsEvent()
        {
            return PredicateBuilder.False<CombatLogEvent>().Or(x => x.IsEvent());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsOutgoingDamage()
        {
            return IsSource().And(IsDamage());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsIncomingDamage()
        {
            return IsTarget().And(IsDamage());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsOutgoingHeal()
        {
            return IsSource().And(TargetIsNotNpc()).And(IsHeal());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsIncomingHeal()
        {
            return IsTarget().And(IsHeal());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsOthersEffect()
        {
            return IsNotTarget().And(IsEffect());
        }
        public static Expression<Func<CombatLogEvent, bool>> IsCharacterEffect()
        {
            return IsTarget().And(IsEffect());
        }
        public static IEnumerable<CombatLogEvent> ApplyFilter(this IEnumerable<CombatLogEvent> source, CombatLogFilterParameters p)
        {
            if (p.ShowAll || p.EffectiveShowAll)
                return source;
            else
            {
                var predicate = PredicateBuilder.False<CombatLogEvent>();
                if (p.ShowAbilities)
                    predicate = predicate.Or(IsAbility());
                if (p.ShowIncomingDamage)
                    predicate = predicate.Or(IsIncomingDamage());
                if (p.ShowOthersEffects)
                    predicate = predicate.Or(IsOthersEffect());
                if (p.ShowIncomingHeals)
                    predicate = predicate.Or(IsIncomingHeal());
                if (p.ShowOutgoingHeals)
                    predicate = predicate.Or(IsOutgoingHeal());
                if (p.ShowOutgoingDamage)
                    predicate = predicate.Or(IsOutgoingDamage());
                if (p.ShowEvents)
                    predicate = predicate.Or(IsEvent());
                if (p.ShowCharacterEffects)
                    predicate = predicate.Or(IsCharacterEffect());
                return source.AsQueryable().Where(predicate);
            }
        }
        public static IEnumerable<string> ApplyFilter(this IEnumerable<string> source, CombatLogFilterParameters p)
        {
            if (!string.IsNullOrEmpty(p.KeyWordFilter))
                return source.Where(x => x.ContainsString(p.KeyWordFilter, true));
            return source;
        }
    }
}
